#pragma once
#include <stdexcept>
using std::runtime_error;

namespace noria {

	//class IString;
	class IType;
	class IReflectable;

	template<class T>
	class AutoDisposable
	{
	public:
		AutoDisposable()
			: m_ptr(nullptr)
		{
		}
		AutoDisposable(T* ptr)
			: m_ptr(ptr)
		{
		}
		AutoDisposable(const AutoDisposable& ref)
			: m_ptr(nullptr)
		{
			throw runtime_error("AutoDisposable pointer doesn't support copy operation");
		}
		AutoDisposable(AutoDisposable&& ref)
			: m_ptr(ref.Detach())
		{
		}
		~AutoDisposable()
		{
			if (m_ptr)
			{
				m_ptr->Dispose();
			}
		}
	public:
		T& operator*() const
		{
			return *m_ptr;
		}
		T* operator->() const
		{
			return m_ptr;
		}
		T* operator&() const
		{
			return m_ptr;
		}
		T* Get() const
		{
			return m_ptr;
		}
		T* Reset(T* ptr)
		{
			Detach();
			m_ptr = ptr;
			return m_ptr;
		}
		T* Detach()
		{
			auto ptr = m_ptr;
			m_ptr = nullptr;
			return ptr;
		}
	private:
		T* m_ptr;
	};
#define DECLARE_DISPOSABLE(T) typedef AutoDisposable<T> T##Ptr
#define DEFAULT_IMPL_DISPOSE() \
		virtual void Dispose() override\
	    {\
			delete this;\
	    }

	class IDisposable
	{
	public:
		virtual void Dispose() = 0;
	};
	DECLARE_DISPOSABLE(IDisposable);

	class IReflectable : public IDisposable
	{
	public:
		virtual const IType* const GetType() const = 0;
		virtual IReflectable* Invoke(const char* name, IReflectable** args = nullptr) = 0;
	};
	DECLARE_DISPOSABLE(IReflectable);

	class IType : public IDisposable
	{
	public:
		virtual IReflectable* CreateInstance() const = 0;
		virtual const char* const GetName() const = 0;
		virtual const char* const GetFullName() const = 0;
	};

	class ITypeCollection : public IDisposable
	{
	public:
		virtual void Add(const char* name, const IType* type) = 0;
	};
	typedef void(*RegisterCallback)(ITypeCollection*);
#define AddType(map, tc, type) \
	tc = type;\
	map->Add(tc->GetFullName(), tc)

}